package com.zjw.processor;

import com.google.auto.service.AutoService;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import com.zjw.annotation.Service;

import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;

/**
 * @author ：zhong.jw
 * @date ：Created in 2022/9/27 8:48
 */
//此注解，表示会执行此类
@AutoService(Processor.class)
public class ServiceProcessor extends AbstractProcessor {

    private ProcessingEnvironment mProcessingEnvironment;

    private final Map<String, CreateServiceProxy> mCache = new HashMap<>();

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.mProcessingEnvironment = processingEnv;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        // 写入支持编译的注解
        Set<String> supportTypes = new HashSet<>();
        supportTypes.add(Service.class.getCanonicalName());
        return supportTypes;
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        // 兼容到JDK最新版本
        return SourceVersion.latestSupported();
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        //动态生成java代码
        mProcessingEnvironment.getMessager().printMessage(Diagnostic.Kind.NOTE, "processing...");
        //获取所有@Service的Element
        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(Service.class);
        for (Element element : elements) {
            VariableElement variableElement = (VariableElement) element;
            TypeElement typeElement = (TypeElement) variableElement.getEnclosingElement();
            String className = typeElement.getQualifiedName().toString();
            Service service = variableElement.getAnnotation(Service.class);
            Class<?> iInterface = service.iInterface();
            CreateServiceProxy proxy = new CreateServiceProxy(mProcessingEnvironment.getElementUtils(), typeElement, iInterface);
            mCache.put(className, proxy);
        }

        //创建java文件
        mProcessingEnvironment.getMessager().printMessage(Diagnostic.Kind.ERROR, "create code :");
        try {
            JavaFileObject javaFileObject = super.processingEnv.getFiler().createSourceFile("ServiceManager");
            Writer writer = javaFileObject.openWriter();
            writer.write(createServiceCode());
            writer.flush();
            writer.close();
        } catch (IOException e) {
            mProcessingEnvironment.getMessager().printMessage(Diagnostic.Kind.ERROR, "fail code :");
        }
        mProcessingEnvironment.getMessager().printMessage(Diagnostic.Kind.ERROR, "finish code :");
        return true;
    }


    private String createServiceCode() {
        return generateJavaCode();
    }

    public String generateJavaCode() {
        TypeSpec.Builder builder = TypeSpec.classBuilder("ServiceManager");

        for (CreateServiceProxy value : mCache.values()) {
            builder.addField(value.getClazz(), value.getFieldName(), Modifier.PRIVATE, Modifier.STATIC);
            builder.addMethod(generateJavaGetServiceMethod(value));
        }

        TypeSpec typeSpec = builder.build();

        // 不知为何，生成代码少package行，导致找不到，这儿暂时这么写
        return "package " +
                "com.zjw.zy.service" +
                ";\n" +
                typeSpec;
    }

    public MethodSpec generateJavaGetServiceMethod(CreateServiceProxy value) {

        MethodSpec.Builder builder = MethodSpec.methodBuilder("get" + value.getClassName() + "Service")//方法名
                .addModifiers(Modifier.PUBLIC)//限定符
                .addModifiers(Modifier.STATIC)//限定符
                .returns(value.getClazz());//返回值

        String field = value.getFieldName();
        //迭代，加入代码行
        builder.addCode("if($N == null){", field);
        builder.addCode("synchronized (this){if($N == null){$N = $N}}", field, field, value.newObject());
        builder.addCode("}");
        builder.addCode("return $N;", field);
        return builder.build();
    }
}